/**
 * Copyright (C) 2010 Jerome Arnaud and Voxisland (www.voxisland.com)
 * Copyright (C) 2008 The Android Open Source Project
 * 
 * This file is part of PokerBlinds.
 *
 *  PokerBlinds is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  PokerBlinds is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with PokerBlinds.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.voxisland.pokerblinds;

import java.text.NumberFormat;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class Main extends Activity {
	private static final int						UNLIMITED									= 999;
	private static final int						MENU_NEW_GAME					= Menu.FIRST;
	private static final int						MENU_CUSTOM_MODEL	= Menu.FIRST + 1;
	private static final int						MENU_SOUND								= Menu.FIRST + 2;
	private static final int						MENU_ABOUT								= Menu.FIRST + 3;
	private static final int						MENU_EXIT									= Menu.FIRST + 4;
	private int																			modelChoice;
	private int																			currentRound;
	private TextView														txt_counter, txt_roundNumber;
	private Button																ima_smallblind, ima_bigblind, ima_ante;
	private ImageView													ima_ante_header;
	private final MyClock									myClock											= new MyClock();
	private Boolean															onPause											= true;
	private final Handler									handler											= new Handler();
	private PowerManager.WakeLock	wakeLock;
	private static final int						SBLIND												= 0;
	private static final int						DURATION										= 1;
	private static final int						ANTE														= 2;
	// Todo: push this in a DB
	private final int[][][]							rounds												= {
																																																	{ { 100, 15, 0 }, { 200, 15, 0 }, { 300, 10, 0 }, { 400, 10, 0 }, { 500, 10, 0 }, { 1000, 10, 0 }, { 1500, 10, 0 }, { 2000, 10, 0 }, { 2500, 10, 0 }, { 3000, 10, 0 }, { 4000, 10, 0 },
																																																	{ 5000, UNLIMITED, 0 } },
																																																	{ { 100, 20, 0 }, { 200, 20, 0 }, { 300, 15, 0 }, { 400, 15, 0 }, { 0, 10, 0 }, { 500, 15, 0 }, { 1000, 15, 0 }, { 1500, 15, 0 }, { 2000, 15, 0 }, { 2500, 15, 0 }, { 0, 10, 0 },
																																																	{ 3000, 15, 0 }, { 4000, 15, 0 }, { 5000, 15, 0 },
																																																	{ 8000, 15, 0 },
																																																	{ 0, 10, 0 }, { 10000, UNLIMITED, 0 } },
																																																	{ { 100, 20, 0 }, { 200, 20, 0 }, { 300, 15, 0 }, { 400, 15, 0 }, { 0, 10, 0 }, { 500, 15, 0 }, { 1000, 15, 0 }, { 1500, 15, 0 }, { 2000, 15, 0 }, { 2500, 15, 0 }, { 0, 10, 0 },
																																																	{ 3000, 15, 0 }, { 4000, 15, 0 }, { 5000, 15, 0 },
																																																	{ 10000, 15, 0 },
																																																	{ 0, 10, 0 }, { 15000, 10, 0 }, { 20000, 10, 0 }, { 25000, 10, 0 }, { 30000, UNLIMITED, 0 } },
																																																	{ { 100, 20, 0 }, { 200, 15, 0 }, { 300, 15, 0 }, { 400, 15, 0 }, { 0, 10, 0 }, { 500, 15, 0 }, { 1000, 15, 0 }, { 1500, 15, 0 }, { 2000, 15, 0 }, { 2500, 15, 0 }, { 0, 10, 0 },
																																																	{ 3000, 10, 0 }, { 4000, 15, 0 }, { 5000, 10, 0 },
																																																	{ 10000, 10, 0 },
																																																	{ 15000, 10, 0 }, { 20000, 10, 0 }, { 25000, 10, 0 }, { 30000, UNLIMITED, 0 } },
																																																	{ { 100, 15, 0 }, { 200, 15, 0 }, { 300, 15, 0 }, { 400, 15, 0 }, { 500, 15, 0 }, { 600, 15, 0 }, { 700, 15, 0 }, { 800, 15, 0 }, { 0, 10, 0 }, { 1000, 15, 0 }, { 1500, 15, 0 },
																																																	{ 2000, 15, 0 }, { 2500, 15, 0 }, { 3000, 15, 0 },
																																																	{ 3500, 15, 0 },
																																																	{ 0, 10, 0 }, { 4000, 15, 0 }, { 5000, 15, 0 }, { 6000, 15, 0 }, { 8000, 15, 0 }, { 10000, 15, 0 }, { 12000, 15, 0 }, { 15000, 15, 0 }, { 20000, 15, 0 }, { 25000, 15, 0 }, { 30000, 15, 0 },
																																																	{ 50000, UNLIMITED, 0 } },
																																																	{ { 100, 15, 0 }, { 200, 15, 0 }, { 300, 10, 0 }, { 400, 10, 0 }, { 500, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 },
																																																	{ 1000, 10, 0 }, { 1000, 10, 0 },
																																																	{ 1000, 10, 0 },
																																																	{ 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 }, { 1000, 10, 0 },
																																																	{ 1000, 10, 0 }, { 1000, 10, 0 },
																																																	{ 1000, 10, 0 },
																																																	{ 1000, 10, 0 }, { 1000, 10, 0 } }
																																																	};

	@Override public void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
		wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "DoNotDimScreen");

		// find views
		final ImageView but_rewind = (ImageView) findViewById(R.id.but_rewind);
		final ImageView but_play = (ImageView) findViewById(R.id.but_play);
		final ImageView but_pause = (ImageView) findViewById(R.id.but_pause);
		final ImageView but_forward = (ImageView) findViewById(R.id.but_forward);
		txt_roundNumber = (TextView) findViewById(R.id.txt_round);
		ima_smallblind = (Button) findViewById(R.id.ima_smallblind);
		ima_bigblind = (Button) findViewById(R.id.ima_bigblind);
		ima_ante = (Button) findViewById(R.id.ima_ante);
		ima_ante_header = (ImageView) findViewById(R.id.ima_ante_header);
		txt_counter = (TextView) findViewById(R.id.clock);

		showModelChooser();

		but_play.setOnClickListener(new OnClickListener() {
			@Override public void onClick(final View v) {
				if (onPause) {
					horn();
					myClock.start();
					onPause = false;
				}
			}
		});

		but_pause.setOnClickListener(new OnClickListener() {
			@Override public void onClick(final View v) {
				if (!onPause) {
					myClock.stop();
					onPause = true;
				}
			}
		});

		but_rewind.setOnClickListener(new OnClickListener() {
			@Override public void onClick(final View v) {
				prevRound();
			}
		});

		but_forward.setOnClickListener(new OnClickListener() {
			@Override public void onClick(final View v) {
				nextRound(true);
			}
		});

		// let's start at the... ...beginning
		round(0);
	}

	@Override protected void onPause() {
		super.onPause();
		wakeLock.release();
		if (!onPause) {
			onPause = true;
			myClock.stop();
		}
	}

	@Override protected void onResume() {
		super.onResume();

		wakeLock.acquire();

		SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
		String s = sp.getString("custom", CustomModel.DEFAULT_CUSTOM_BLINDS);
		StringTokenizer st = new StringTokenizer(s);
		try {
			for (int round = 0; round < CustomModel.CUSTOM_BLINDS_NB_ROUNDS; round++) {
				rounds[5][round][SBLIND] = Integer.valueOf(st.nextToken());
				rounds[5][round][ANTE] = Integer.valueOf(st.nextToken());
				rounds[5][round][DURATION] = Integer.valueOf(st.nextToken());
			}
		} catch (Exception e) {
			// something went wrong, let's consider the saved value is corrupted or of a
			// previous format
			Log.e("PokerBlinds", "corrupted model?");
			s = CustomModel.DEFAULT_CUSTOM_BLINDS;
			st = new StringTokenizer(s);
			for (int round = 0; round < CustomModel.CUSTOM_BLINDS_NB_ROUNDS; round++) {
				rounds[5][round][SBLIND] = Integer.valueOf(st.nextToken());
				rounds[5][round][ANTE] = Integer.valueOf(st.nextToken());
				rounds[5][round][DURATION] = Integer.valueOf(st.nextToken());
			}
		}

	}

	@Override public boolean onCreateOptionsMenu(final Menu menu) {
		menu.add(Menu.NONE, MENU_NEW_GAME, Menu.NONE, getResources().getText(R.string.new_game)).setIcon(R.drawable.menu_newgame);
		menu.add(Menu.NONE, MENU_CUSTOM_MODEL, Menu.NONE, getResources().getText(R.string.change_custom)).setIcon(R.drawable.menu_config);
		menu.add(Menu.NONE, MENU_SOUND, Menu.NONE, getResources().getText(R.string.change_sound)).setIcon(R.drawable.menu_sound);
		menu.add(Menu.NONE, MENU_ABOUT, Menu.NONE, getResources().getText(R.string.about)).setIcon(R.drawable.menu_info);
		menu.add(Menu.NONE, MENU_EXIT, Menu.NONE, getResources().getText(R.string.exit)).setIcon(R.drawable.menu_exit);
		return super.onCreateOptionsMenu(menu);
	}

	@Override public boolean onOptionsItemSelected(final MenuItem item) {
		Intent gonext;

		switch (item.getItemId()) {
			case MENU_NEW_GAME:
				if (!onPause) {
					onPause = true;
					myClock.stop();
				}
				showModelChooser();
				break;
			case MENU_CUSTOM_MODEL:
				gonext = new Intent(Main.this, CustomModel.class);
				startActivity(gonext);
				break;
			case MENU_SOUND:
				gonext = new Intent(Main.this, Sound.class);
				startActivity(gonext);
				break;
			case MENU_ABOUT:
				gonext = new Intent(Main.this, AboutScreen.class);
				startActivity(gonext);
				break;
			case MENU_EXIT:
				finish();
				break;
		}
		return super.onOptionsItemSelected(item);
	}

	private void showModelChooser() {
		final String[] models = {
				(String) this.getResources().getText(R.string.sit_n_go_8_10_players),
				(String) this.getResources().getText(R.string.tourn_8_20_players),
				(String) this.getResources().getText(R.string.tourn_21_40_players),
				(String) this.getResources().getText(R.string.tourn_41_70_players),
				(String) this.getResources().getText(R.string.mega_tourn_75_players),
				(String) this.getResources().getText(R.string.custom_model)
			};
		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.choose_a_blind_model);
		builder.setItems(models, new DialogInterface.OnClickListener() {
			public void onClick(final DialogInterface dialog, final int item) {
				final TextView txt_model = (TextView) findViewById(R.id.txt_model);
				txt_model.setText(models[item]);
				modelChoice = item;
				currentRound = 0;
				round(0);
			}
		});
		final AlertDialog alert = builder.create();
		alert.show();
	}

	private void updateDisplay() {
		if (myClock.duration == UNLIMITED * 60) {
			txt_counter.setText(getText(R.string.no_limit));
			return;
		}

		final Integer minutes = myClock.remains / 60;
		final Integer seconds = myClock.remains - 60 * minutes;
		final NumberFormat nf = NumberFormat.getInstance();
		nf.setMinimumIntegerDigits(2);

		txt_counter.setText(nf.format(minutes) + ":" + nf.format(seconds));
	}

	private void haveABreak() {
		ima_smallblind.setVisibility(View.INVISIBLE);
		ima_bigblind.setVisibility(View.INVISIBLE);
		ima_ante.setVisibility(View.INVISIBLE);
		txt_roundNumber.setTextColor(Color.RED);
		txt_roundNumber.setText(getText(R.string._break_));
	}

	private void round(final int r) {

		// break ? no more rounds ?
		if (rounds[modelChoice][r][SBLIND] == 0) {
			if (rounds[modelChoice][r][DURATION] == 0) {
				if (!onPause)
					myClock.stop();
				return;
			} else {
				// break
				haveABreak();
				updateDisplay();
				myClock.set(rounds[modelChoice][r][DURATION] * 60);
				updateDisplay();
				if (!onPause)
					myClock.start();
				return;
			}
		}

		txt_roundNumber.setTextColor(Color.WHITE);
		ima_smallblind.setVisibility(View.VISIBLE);
		ima_bigblind.setVisibility(View.VISIBLE);
		ima_smallblind.setText(Integer.toString(rounds[modelChoice][r][SBLIND]));
		ima_bigblind.setText(Integer.toString(rounds[modelChoice][r][SBLIND] * 2));

		if (rounds[modelChoice][r][ANTE] == 0) {
			ima_ante.setVisibility(View.GONE);
			ima_ante_header.setVisibility(View.GONE);
		} else {
			ima_ante.setVisibility(View.VISIBLE);
			ima_ante_header.setVisibility(View.VISIBLE);
			ima_ante.setText(Integer.toString(rounds[modelChoice][r][ANTE]));
		}
		// we're cheating since breaks are considered as round, now we need to
		// calculate the
		// real rounds number
		int realRound = 0;
		for (int i = 0; i <= r; i++) {
			if (rounds[modelChoice][i][SBLIND] != 0)
				realRound++;
		}
		txt_roundNumber.setText(getText(R.string.round) + " " + (realRound));

		if (rounds[modelChoice][r][SBLIND] != 0) {
			myClock.set(rounds[modelChoice][r][DURATION] * 60);
			updateDisplay();
			if (!onPause)
				myClock.start();
		}

	}

	private void nextRound(final Boolean withStop) {
		if (currentRound + 1 < rounds[modelChoice].length) {
			if (withStop && !onPause)
				myClock.stop();
			round(++currentRound);
		}
	}

	private void prevRound() {
		if (!onPause)
			myClock.stop();
		if (currentRound - 1 >= 0) {
			round(--currentRound);
		} else
			myClock.reset();
	}

	private void horn() {
		new Thread(new Runnable() {
			public void run() {
				SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(Main.this);
				String s = sp.getString("buzzer", "");

				MediaPlayer mp;
				if (s != "" && s != null) {
					Uri u = Uri.parse(s);
					mp = MediaPlayer.create(Main.this, u);
				} else {
					mp = MediaPlayer.create(Main.this, R.raw.airhorn);
				}
				mp.start();
				Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
				v.vibrate(1000);

				try {
					Thread.sleep(6000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				mp.stop();
			}
		}).start();
	}

	public class MyClock {
		private int			duration;
		public int				remains;
		private Timer	timer;

		public void onTimesup() {
			stop();
			horn();
			handler.post(launchNextRound);
		}

		public void start() {
			timer = new Timer();
			timer.schedule(new TimerTask() {
				@Override public void run() {
					onTick();
				}
			}, 0, 1000);
		}

		public void stop() {
			timer.cancel();
		}

		public void set(final int zduration) {
			duration = remains = zduration;
		}

		public void reset() {
			remains = duration;
			handler.post(updateDisplay);
		}

		final Runnable	updateDisplay			= new Runnable() {
																																		public void run() {
																																			updateDisplay();
																																		}
																																	};

		final Runnable	launchNextRound	= new Runnable() {
																																		public void run() {
																																			nextRound(false);
																																		}
																																	};

		public void onTick() {
			remains -= 1;
			if (remains == 0)
				onTimesup();
			handler.post(updateDisplay);
		}

	}

}